package cn.zbacm.api.security.service;

import cn.zbacm.api.security.constant.AuthError;
import cn.zbacm.api.util.ServiceResult;
import com.fasterxml.jackson.core.JsonProcessingException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

@Slf4j
@Service
public class SecurityService {
    @Autowired
    private DaoAuthenticationProvider authenticationProvider;

    @Autowired
    private CustomUserDetailsService customUserDetailsService;

    @Autowired
    private JwtTokenProvider tokenProvider;

    public ServiceResult<String> authenticate(String loginId, String password)
            throws JsonProcessingException {
        ServiceResult<String> result = new ServiceResult<>(false);
        log.info("login id [{}] try to login", loginId);
        log.info("password has text: {}", StringUtils.hasText(password));

        try {
            Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
            if (authentication instanceof AnonymousAuthenticationToken) {
                UserDetails userDetails = customUserDetailsService.loadUserByUsername(loginId);
                log.info("userDetails loaded");
                UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken =
                        new UsernamePasswordAuthenticationToken(userDetails, password, null);
                log.info("authentication token loaded");
                authentication = authenticationProvider.authenticate(usernamePasswordAuthenticationToken);
            } else {
                log.warn("user has logged in before!");
            }

            log.info("authentication loaded");
            String jwt = tokenProvider.generateToken(authentication);
            log.info("jwt loaded");

            result.setData(jwt);
            result.setSuccess(true);
        } catch (UsernameNotFoundException err) {
            log.info("login id [{}] not found", loginId);
            result.setMessageCode(AuthError.LOGIN_ID_NOT_FOUND);
        } catch (BadCredentialsException err) {
            log.info("login id [{}] provides wrong password", loginId);
            result.setMessageCode(AuthError.WRONG_PASSWORD);
        }

        return result;
    }
}
